Панель управления — Tools API
Версия: 1.3
Дата: 22.04.2026
Статус: Утверждён
Панель управления документацией — браузерный интерфейс для запуска всех скриптов системы без терминала. Состоит из двух частей: API-сервер (tools/cms-tools-api.js) и страница интерфейса (static/admin/tools.html).
Открывается по адресу: http://localhost:3000/admin/tools.html
Из CMS-редактора — кнопка Инструменты в правом верхнем углу шапки.
Архитектура
Браузер (tools.html)
│
├── GET /projects — список проектов из docs/
├── GET /run/<script> — запуск скрипта, SSE-поток вывода
├── GET /convert — конвертация SVG или возврат к SVG
├── GET /deploy-convert — деплой с опциональной конвертацией
└── POST /import — upload файла + запуск import_bundle.sh
CMS Tools API (порт 8084)
└── запускает bash-скрипты из tools/ в корне репозитория
SSE (Server-Sent Events) — вывод скрипта стримится в браузер построчно в реальном времени. Соединение закрывается когда скрипт завершается.
Установка и запуск
Зависимости
npm install --save-dev express multer
Устанавливается один раз. Пакеты express и multer нужны только API-серверу.
Ручной запуск
node tools/cms-tools-api.js
# или с кастомным портом:
PORT=8084 node tools/cms-tools-api.js
Автозапуск через pm2
API-сервер уже добавлен в ecosystem.config.js — стартует автоматически вместе с остальными процессами:
# Первый запуск (все три процесса):
pm2 start ecosystem.config.js
# Только API:
pm2 start ecosystem.config.js --only cms-tools-api
# Перезапуск после обновления кода:
pm2 restart cms-tools-api
Конфигурация в ecosystem.config.js:
{
name: 'cms-tools-api',
script: 'tools/cms-tools-api.js',
cwd: '/home/alex/sites/cms-docs',
env: { PORT: '8084' },
}
Автостарт при перезагрузке системы
# Выполнить один раз — генерирует systemd unit:
pm2 startup
# Сохранить список процессов:
pm2 save
После этого все три процесса (cms-docs-dev, cms-decap-server, cms-tools-api) запустятся автоматически при старте системы.
Настройка
Порт
По умолчанию API слушает порт 8084. Изменить через переменную окружения PORT:
PORT=9000 node tools/cms-tools-api.js
Или в ecosystem.config.js:
{
name: 'cms-tools-api',
script: 'tools/cms-tools-api.js',
cwd: '/home/alex/sites/cms-docs',
env: { PORT: '8084' },
}
Если порт 8084 занят — проверить:
ss -tlnp | grep 8084
Занятый порт — поменять в ecosystem.config.js и обновить константу API в static/admin/tools.html:
const API = 'http://localhost:8084'; // строка 2 блока <script>
Путь к репозиторию
API определяет корень репозитория автоматически через path.resolve(__dirname, '..') — то есть на директорию выше tools/. Если скрипт запускается из другого места — путь всё равно будет правильным, так как привязан к расположению файла, а не к рабочей директории.
ecosystem.config.js — полный пример
Файл в корне репозитория управляет всеми тремя процессами:
module.exports = {
apps: [
// Docusaurus dev-сервер — сайт + CMS
{
name: 'cms-docs-dev',
script: 'npm',
args: 'start',
cwd: '/home/alex/sites/cms-docs',
watch: false,
autorestart: true,
env: { NODE_ENV: 'development' },
},
// Decap CMS прокси для git-операций
{
name: 'cms-decap-server',
script: 'npx',
args: 'decap-server',
cwd: '/home/alex/sites/cms-docs',
watch: false,
autorestart: true,
env: { PORT: '8083' },
},
// Tools API — панель управления
{
name: 'cms-tools-api',
script: 'tools/cms-tools-api.js',
cwd: '/home/alex/sites/cms-docs',
watch: false,
autorestart: true,
env: { PORT: '8084' },
},
],
};
Параметры:
| Параметр | Значение | Назначение |
|---|---|---|
name | строка | Имя процесса в pm2 — используется в командах pm2 restart/stop/logs |
script | путь или команда | Что запускать |
args | аргументы | Передаются в script |
cwd | абсолютный путь | Рабочая директория — обязательно абсолютный путь |
watch | false | Не перезапускать при изменении файлов (dev-сервер сам следит) |
autorestart | true | Перезапускать если процесс упал |
env.PORT | число | Порт для процесса |
Изменить cwd если репозиторий лежит в другой папке — иначе процессы не найдут файлы.
Где хранит настройки pm2
pm2 хранит свои данные в ~/.pm2/:
~/.pm2/
dump.pm2 — сохранённый список процессов (pm2 save)
logs/ — логи всех процессов
cms-tools-api-out.log
cms-tools-api-error.log
pids/ — PID-файлы запущенных процессов
Полезные команды:
pm2 logs cms-tools-api # хвост логов в реальном времени
pm2 logs cms-tools-api --lines 100 # последние 100 строк
pm2 flush # очистить все логи
pm2 show cms-tools-api # подробная информация о процессе
pm2 monit # интерактивный мониторинг CPU/RAM
Переменные окружения
API наследует весь process.env от pm2/shell и передаёт его в дочерние скрипты. Если скрипты деплоя используют переменные окружения (SSH-ключи, токены) — добавить их в секцию env в ecosystem.config.js:
env: {
PORT: '8084',
SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK, // пробросить ssh-agent
}
Или задать глобально через ~/.bashrc / ~/.profile — pm2 подхватит при запуске через systemd только если --hp указывает на правильный home.
tools.html — где менять настройки интерфейса
Файл static/admin/tools.html. Все настраиваемые параметры в начале блока <script>:
const API = 'http://localhost:8084'; // адрес API-сервера
Если изменили порт API — поменять здесь. Остальные параметры (список скриптов, логика) живут в tools/cms-tools-api.js.
Проверка работы
# Статус процессов:
pm2 list
# Логи API:
pm2 logs cms-tools-api
# Быстрая проверка через curl:
curl http://localhost:8084/projects
Ответ должен вернуть JSON со списком проектов.
Три запущенных процесса
| Имя pm2 | Порт | Назначение |
|---|---|---|
cms-docs-dev | 3000 | Docusaurus dev-сервер, сайт и CMS |
cms-decap-server | 8083 | Decap CMS прокси для git-операций |
cms-tools-api | 8084 | API для запуска скриптов из браузера |
Интерфейс панели
Шапка
Тёмная полоса вверху. Содержит название и ссылку ← CMS — возврат в редактор.
Строка выбора проекта
Проект: [ выпадающий список ] [ badge с текущим slug ]
Список проектов загружается автоматически при открытии страницы — читаются все папки docs/ у которых есть _project_.json. При открытии панели из CMS-редактора (через кнопку "Инструменты") slug определяется автоматически из URL редактора.
Выбор проекта влияет на все операции блока Текущий проект.
Блок: Текущий проект
Операции над выбранным проектом. Перед нажатием — выбрать проект в строке выше.
| Кнопка | Скрипт | Что делает |
|---|---|---|
| Экспорт архива | export_project.sh <slug> | Создаёт exports/<slug>-YYYY-MM-DD.tar.gz без паролей и .gitkeep. Архив можно передать другому человеку. |
| Бандл для ревью | bundle_for_review.sh <slug> | Склеивает все MD-файлы проекта в один текстовый файл и упаковывает в .tar.gz. Для передачи документации проекта в AI с большим контекстным окном. |
| Пересобрать index.md | build_project_index.sh <slug> | Регенерирует docs/<slug>/index.md на основе _project_.json и _category_.json разделов. Нужно запускать после добавления новых документов или разделов. |
| Синхр. assets | sync_assets.sh <slug> | Копирует файлы из docs/<slug>/assets/ в static/<slug>/. Нужно после добавления новых медиафайлов чтобы они стали доступны на сайте. |
Конвертация изображений
Позволяет конвертировать SVG-диаграммы проекта в растровый формат и обратно. SVG-исходники при этом никогда не удаляются — они остаются рядом как мастер-файлы.
Зачем это нужно. SVG отлично работают на современных браузерах, но некоторые платформы (почта, PDF, мессенджеры, старые просмотрщики) их не поддерживают. Конвертация позволяет задеплоить сайт с растровыми изображениями, не теряя векторные исходники.
Как работает конвертация:
- Скрипт
tools/convert_svg.shнаходит все.jpgфайлы вdocs/<slug>/assets/ - Рендерит каждый через Inkscape (DPI 150, белый фон) → экспортирует в PNG
- Для JPEG — дополнительно конвертирует PNG → JPEG через ImageMagick (качество 85)
- Результат кладёт рядом с SVG:
vitrip_xxx.jpg→vitrip_xxx.jpg - Дублирует файл в
static/<slug>/если там есть SVG-оригинал (чтобы сайт подхватил) - Патчит все MD-файлы проекта: заменяет расширение
.jpg→.jpg/.jpgв ссылках
| Кнопка | Что делает |
|---|---|
| SVG → JPEG | Конвертирует все SVG проекта в JPEG, патчит ссылки в MD на .jpg |
| SVG → PNG | Конвертирует все SVG проекта в PNG, патчит ссылки в MD на .jpg |
| ↩ Вернуть SVG | Удаляет конвертированные файлы (только если есть SVG-оригинал), патчит ссылки обратно на .jpg |
После конвертации — MD-файлы проекта ссылаются на JPEG/PNG, сайт показывает растровые изображения. SVG рядом, можно вернуть в любой момент.
Зависимости: inkscape и imagemagick должны быть установлены на машине:
sudo apt install inkscape imagemagick
Деплой проекта
Публикация одного выбранного проекта на сервер. Полная пересборка сайта происходит всегда — Docusaurus не умеет собирать частично. Но на сервер уходит только папка выбранного проекта плюс общие assets (JS/CSS/img). Это экономит трафик и время передачи данных.
Зачем нужно. Когда проектов много, а изменился только один — нет смысла заливать всё целиком. Деплой проекта синхронизирует именно его папку без риска затронуть другие проекты на сервере.
Таблица кнопок аналогична полному деплою — 3 метода × 3 формата изображений. Логика та же: JPEG/PNG сначала конвертирует SVG только этого проекта, затем деплоит.
| Метод | SVG | JPEG | PNG |
|---|---|---|---|
| Shared | rsync только build/<slug>/ + assets | + конвертация перед деплоем | + конвертация перед деплоем |
| VPS docker | rsync + docker compose up -d | + конвертация | + конвертация |
| VPS pm2 | rsync + pm2 restart | + конвертация | + конвертация |
При деплое одного проекта
--deleteне передаётся в rsync — удалённые файлы других проектов на сервере не затрагиваются. При полном деплое--deleteесть — сервер синхронизируется полностью.
Добавить пользователя в проект
[ логин ] [ пароль ] [ Добавить ]
Вызывает add_user.sh <slug> <username> <password>. Генерирует два хэша и записывает в access[] файла docs/<slug>/_project_.json:
cms_hash— SHA-256 отusername:passwordдля JS-аутентификации в браузереpassword_hash— SHA-512 htpasswd-совместимый хэш (генерируется для совместимости, текущей аутентификацией не используется)
Если пользователь уже существует — оба хэша обновляются. После добавления система автоматически вызывает build_auth.sh для обновления JS-модуля.
Блок: Глобальные операции
Операции на всю систему, не зависят от выбранного проекта.
| Кнопка | Скрипт | Что делает |
|---|---|---|
| Пересобрать главную | build_index.sh | Регенерирует docs/index.md — главную страницу со списком всех публичных проектов (public: true). Запускать после добавления нового проекта или изменения его метаданных. |
| Синхр. все assets | sync_assets.sh | Синхронизирует assets/ всех проектов в static/ — без аргумента скрипт обрабатывает все проекты сразу. |
| Экспорт публичных | export_public.sh | Экспортирует все проекты с public: true — вызывает export_project.sh для каждого. Архивы сохраняются в exports/. |
| Пересобрать доступы | build_auth.sh | Регенерирует src/auth/project-access.js из всех _project_.json. Запускать после добавления/изменения пользователей если не хочется делать полную сборку. Автоматически вызывается как prebuild при npm run build. |
| Бандл всех для ревью | bundle_for_review.sh --all | Склеивает все MD-файлы каждого проекта в один текстовый файл и упаковывает в .tar.gz. Нужна для передачи всей документации в AI с большим контекстным окном. Архивы сохраняются в exports/. |
JS-аутентификация
Система защиты проектов работает на стороне браузера — поверх статического сайта, без серверной логики.
Схема:
_project_.json (access[].cms_hash)
↓
tools/build_auth.sh
↓
src/auth/project-access.js ← ES-модуль, встраивается в сборку
↓
src/clientModules/authGuard.js ← хук onRouteUpdate, проверяет каждый переход
src/pages/login.tsx ← страница /login, SHA-256 верификация
Жизненный цикл токена:
- При успешном входе:
localStorage['docs-auth:<slug>'] = cms_hash - При каждом переходе:
authGuard.jsсравнивает токен сproject-access.js - Разные проекты — независимые токены
- Токен живёт до смены браузера или явной очистки
prebuild в package.json гарантирует что build_auth.sh запускается автоматически перед каждым npm run build. Кнопка Деплой в панели это учитывает.
Кнопка "Пересобрать доступы" (build_auth) — обновляет только JS-модуль без полной пересборки сайта. Удобна после добавления пользователя через "Добавить пользователя", когда нужно проверить результат локально.
Блок: Полный деплой всех проектов
Операции публикации на удалённый сервер. Требуют настроенного cms-config.json с секциями shared или vps.
Блок организован в виде таблицы 3 × 3: три метода деплоя по строкам, три формата изображений по столбцам.
SVG JPEG PNG
Shared ▲ Shared ▲ Shared·jpg ▲ Shared·png
VPS docker ▲ VPS ▲ VPS·jpg ▲ VPS·png
VPS pm2 ▲ VPS ▲ VPS·jpg ▲ VPS·png
Форматы изображений
SVG — деплой без конвертации. Изображения в MD остаются с расширением .jpg, сборка и деплой идут как есть.
JPEG / PNG — перед деплоем автоматически:
- Запускается
convert_svg.sh --action=convert --format=jpeg --slug=all— конвертирует SVG всех проектов, патчит MD-ссылки - Запускается полный деплой (
deploy_site.sh)
MD-файлы и конвертированные изображения остаются в том состоянии после деплоя — ссылки не откатываются назад. Если нужно вернуться к SVG — использовать кнопку ↩ Вернуть SVG в блоке "Текущий проект".
Методы деплоя
| Метод | Скрипт | Что делает |
|---|---|---|
| Shared | deploy_site.sh --mode=shared | Сборка → rsync на shared хостинг |
| VPS docker | deploy_site.sh --mode=vps --method=docker | Сборка → rsync → docker compose up -d на VPS |
| VPS pm2 | deploy_site.sh --mode=vps --method=pm2 | Сборка → rsync → pm2 restart на VPS |
Метод VPS по умолчанию берётся из cms-config.json → vps.deploy_method. Кнопки явно переопределяют метод флагом --method.
Порядок внутри деплоя: одна кнопка делает всё — sync assets → build index → npm run build (включая prebuild с build_auth.sh) → передача на сервер → перезапуск.
Подробнее о настройке VPS: Деплой на VPS — Docker + Traefik
API-эндпоинты
deploy_access_*иdeploy_push_*сохранены для совместимости, но являются stub — ничего не генерируют и не заливают. Кнопки в интерфейсе панели удалены. Аутентификация полностью встроена в JS-бандл.
Блок: Импорт документов
Принимает архив с документами от другого человека или системы и создаёт изолированную ветку import/<id> для ревью.
Как использовать
- Перетащить файл в область или кликнуть для выбора
- Опционально — ввести имя оператора (кто выполняет импорт, для лога)
- Нажать Импортировать
- В консоли справа появится вывод скрипта с именем созданной ветки
Поддерживаемые форматы:
.bundle— git bundle (создаётся черезgit bundle create).tar.gz— архив с папкой проекта (с.gitили без).zip— то же самое в формате zip
После импорта — в консоли будет:
Done. Branch 'import/bundle-2026-04-21-v01' created.
Затем в терминале:
git diff main..import/bundle-2026-04-21-v01 --stat # посмотреть изменения
git merge import/bundle-2026-04-21-v01 # принять
Панель вывода (консоль)
Правая тёмная колонка — отображает вывод запущенного скрипта в реальном времени.
Цвета:
- Синий — команда которая запущена (
$ tools/export_project.sh ...) - Белый — stdout скрипта
- Красный — stderr скрипта
- Бирюзовый — успешное завершение (
✓ Завершено) - Красный жирный — ошибка (
✗ Ошибка)
Статус в правом верхнем углу консоли:
| Статус | Значение |
|---|---|
готов | Ожидает операции |
выполняется... | Скрипт запущен |
готов (синий) | Последняя операция завершилась успешно |
ошибка (красный) | Последняя операция завершилась с ошибкой |
Футер консоли:
- Слева —
API: порт 8084 ✓(зелёный) илиAPI: недоступен(красный) — проверяется при загрузке страницы - Справа — кнопка Очистить — очищает вывод
API эндпоинты
Для прямого использования или интеграции.
GET /projects
Возвращает список всех проектов.
curl http://localhost:8084/projects
[
{ "slug": "vitiana-api-platform", "label": "Vitiana API Platform", "public": false },
{ "slug": "cms-system", "label": "Система документации", "public": false }
]
GET /run/:name?slug=<slug>
Запускает скрипт. Возвращает SSE-поток.
curl http://localhost:8084/run/export_project?slug=vitiana-api-platform
Доступные значения :name:
| name | Нужен slug | Скрипт |
|---|---|---|
export_project | да | export_project.sh |
build_project_index | да | build_project_index.sh |
sync_assets | нет | sync_assets.sh |
build_index | нет | build_index.sh |
build_auth | нет | build_auth.sh — регенерирует src/auth/project-access.js |
export_public | нет | export_public.sh |
serve_preview | нет | serve_preview.sh |
deploy_site_shared | нет | deploy_site.sh --mode=shared |
deploy_site_vps | нет | deploy_site.sh --mode=vps |
deploy_access_shared | нет | deploy_access.sh --mode=shared (stub — ничего не делает) |
deploy_access_vps | нет | deploy_access.sh --mode=vps (stub — ничего не делает) |
deploy_push_shared | нет | deploy_push.sh --mode=shared (stub — ничего не делает) |
deploy_push_vps | нет | deploy_push.sh --mode=vps (stub — ничего не делает) |
add_user | да | add_user.sh (+ username, password) |
bundle_for_review | да | bundle_for_review.sh <slug> |
bundle_all_for_review | нет | bundle_for_review.sh --all |
Формат SSE-событий:
data: {"type":"start","cmd":"tools/export_project.sh vitiana-api-platform"}
data: {"type":"stdout","text":"Exporting vitiana-api-platform...\n"}
data: {"type":"stderr","text":""}
data: {"type":"done","code":0}
GET /convert
Конвертирует SVG проекта в JPEG/PNG или возвращает обратно к SVG. Возвращает SSE-поток.
Параметры:
| Параметр | Значение | Обязательный |
|---|---|---|
action | convert или revert | да |
format | jpeg или png | да (только для convert) |
slug | slug проекта или all | нет — без slug обрабатывает все проекты |
# Конвертировать проект в JPEG
curl "http://localhost:8084/convert?action=convert&format=jpeg&slug=vitiana-api-platform"
# Конвертировать все проекты в PNG
curl "http://localhost:8084/convert?action=convert&format=png&slug=all"
# Вернуть к SVG
curl "http://localhost:8084/convert?action=revert&slug=vitiana-api-platform"
Что происходит при convert:
- Все
.jpgизdocs/<slug>/assets/конвертируются через Inkscape → PNG, затем (для JPEG) через ImageMagick - Результат кладётся рядом:
vitrip_xxx.jpg→vitrip_xxx.jpg - Файл дублируется в
static/<slug>/если там есть SVG-оригинал - В MD-файлах проекта расширение в ссылках заменяется:
.jpg→.jpg/.jpg
Что происходит при revert:
- Удаляются
.jpg/.jpg/.jpgфайлы у которых есть SVG-оригинал (конвертированные) - В MD-файлах расширение возвращается обратно:
.jpg/.jpg→.jpg
SVG-исходники никогда не удаляются.
GET /deploy-convert
Деплой с опциональной предварительной конвертацией SVG. Возвращает SSE-поток.
Параметры:
| Параметр | Значение | Обязательный |
|---|---|---|
mode | shared или vps | да |
method | docker или pm2 | нет (для VPS — берётся из cms-config.json) |
format | svg, jpeg или png | да |
# Деплой Shared с изображениями в JPEG
curl "http://localhost:8084/deploy-convert?mode=shared&format=jpeg"
# Деплой VPS Docker с PNG
curl "http://localhost:8084/deploy-convert?mode=vps&method=docker&format=png"
# Деплой Shared без конвертации (SVG как есть)
curl "http://localhost:8084/deploy-convert?mode=shared&format=svg"
Порядок выполнения при format=jpeg/png:
/convert?action=convert&format=<format>&slug=all— конвертирует все проектыdeploy_site.sh --mode=<mode> [--method=<method>]— полный деплой
При format=svg — только деплой, без конвертации.
POST /import
Загружает файл и запускает импорт. Multipart form-data.
curl -X POST http://localhost:8084/import \
-F "file=@bundle.tar.gz" \
-F "operator=alex"
Возвращает SSE-поток аналогично /run.
Безопасность
API работает только на localhost и не слушает внешние интерфейсы. Предназначен исключительно для локального использования.
Если сервер задеплоен на VPS и нужен доступ к панели удалённо — пробросить порт через SSH:
ssh -L 8084:localhost:8084 user@your-server.com
После этого панель будет доступна локально на http://localhost:3000/admin/tools.html как обычно, но скрипты будут выполняться на сервере.
Не открывать порт 8084 наружу — нет аутентификации, любой сможет запускать скрипты.